{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "参考：[代码实现—Deep Learning with Differential Privacy](https://zhuanlan.zhihu.com/p/614687171)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/anaconda3/envs/science39/lib/python3.9/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: /opt/anaconda3/envs/science39/lib/python3.9/site-packages/torchvision/image.so: undefined symbol: _ZN3c1017RegisterOperatorsD1Ev\n",
      "  warn(f\"Failed to load image Python extension: {e}\")\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import numpy as np\n",
    "from torchvision import datasets, transforms\n",
    "from torch.utils.data import DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm import tqdm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MomentsAccountant:\n",
    "    \"\"\"矩母统计\n",
    "\n",
    "    利用矩母函数估计隐私损失\n",
    "\n",
    "    详见论文：Abadi M, Chu A, Goodfellow I, et al. Deep learning with differential privacy[C]//Proceedings of the 2016 ACM SIGSAC conference on computer and communications security. 2016: 308-318.\n",
    "\n",
    "    论文连接：https://arxiv.org/pdf/1607.00133.pdf%20.\n",
    "\n",
    "    Examples\n",
    "    --------\n",
    "    >>> import MomentsAccount\n",
    "    >>> accountant = MomentsAccount()\n",
    "    >>> epsilon, delta = accountant.get_privacy_spent(4, 0.01, 10000, 1e-5)\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, moment_orders=32):\n",
    "        self.moment_orders = moment_orders\n",
    "\n",
    "    def compute_moment(self, sigma, q, lmbd):\n",
    "        lmbd_int = int(math.ceil(lmbd))\n",
    "        if lmbd_int == 0:\n",
    "            return 1.0\n",
    "\n",
    "        a_lambda_first_term_exact = 0\n",
    "        a_lambda_second_term_exact = 0\n",
    "        for i in range(lmbd_int + 1):\n",
    "            coef_i = scipy.special.binom(lmbd_int, i) * (q ** i) * (1 - q) ** (lmbd - i)\n",
    "            s1, s2 = 0, 0\n",
    "            s1 = coef_i * np.exp((i * i - i) / (2.0 * (sigma ** 2)))\n",
    "            s2 = coef_i * np.exp((i * i + i) / (2.0 * (sigma ** 2)))\n",
    "            a_lambda_first_term_exact += s1\n",
    "            a_lambda_second_term_exact += s2\n",
    "\n",
    "        a_lambda_exact = ((1.0 - q) * a_lambda_first_term_exact +\n",
    "                          q * a_lambda_second_term_exact)\n",
    "\n",
    "        return a_lambda_exact\n",
    "\n",
    "    def compute_log_moment(self, sigma, q, steps):\n",
    "        log_moments = []\n",
    "\n",
    "        for lmbd in range(self.moment_orders + 1):\n",
    "            log_moment = 0\n",
    "            moment = self.compute_moment(sigma, q, lmbd)\n",
    "            log_moment += np.log(moment) * steps\n",
    "            log_moments.append((lmbd, log_moment))\n",
    "        return log_moments\n",
    "\n",
    "    def _compute_eps(self, log_moments, delta):\n",
    "        min_eps = float(\"inf\")\n",
    "\n",
    "        for moment_order, log_moment in log_moments:\n",
    "            if moment_order == 0:\n",
    "                continue\n",
    "            if math.isinf(log_moment) or math.isnan(log_moment):\n",
    "                print(\"The %d-th order is inf or Nan\\n\" % moment_order)\n",
    "                continue\n",
    "            min_eps = min(min_eps, (log_moment - math.log(delta)) / moment_order)\n",
    "            \n",
    "        return min_eps\n",
    "\n",
    "    def get_privacy_spent(self, sigma, q, steps, target_delta):\n",
    "        log_moments = self.compute_log_moment(sigma, q, steps)\n",
    "\n",
    "        return self._compute_eps(log_moments, target_delta), target_delta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# GRU 模型定义\n",
    "class GRUModel(nn.Module):\n",
    "    def __init__(self, vocab_size, embed_dim, hidden_dim, output_dim):\n",
    "        super(GRUModel, self).__init__()\n",
    "        self.embedding = nn.Embedding(vocab_size, embed_dim)\n",
    "        self.gru = nn.GRU(embed_dim, hidden_dim, batch_first=True)\n",
    "        self.fc = nn.Linear(hidden_dim, output_dim)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.embedding(x)\n",
    "        _, h_n = self.gru(x)  # 仅取最终隐藏状态\n",
    "        x = self.fc(h_n.squeeze(0))\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 数据加载与预处理\n",
    "def load_dataset(batch_size):\n",
    "    train_loader = DataLoader(\n",
    "        datasets.MNIST(\n",
    "            './data',\n",
    "            train=True, download=True, \n",
    "            transform=transforms.Compose([\n",
    "                transforms.ToTensor(),\n",
    "                transforms.Normalize((0.1307,), (0.3081,))\n",
    "            ])\n",
    "        ),\n",
    "        batch_size=batch_size,\n",
    "        shuffle=True\n",
    "    )\n",
    "\n",
    "    test_loader = DataLoader(\n",
    "        datasets.MNIST(\n",
    "            './data',\n",
    "            train=False, download=True, \n",
    "            transform=transforms.Compose([\n",
    "                transforms.ToTensor(),\n",
    "                transforms.Normalize((0.1307,), (0.3081,))\n",
    "            ])\n",
    "        ),\n",
    "        batch_size=batch_size,\n",
    "        shuffle=False\n",
    "    )\n",
    "\n",
    "    return train_loader, test_loader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def dp_sgd_train_step(model, X_data, Y_label, loss_func, args):\n",
    "    \"\"\"\n",
    "    单个批次数据的差分隐私随机梯度下降训练步骤。\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    model : torch.nn.Module\n",
    "        训练模型.\n",
    "\n",
    "    X_data : torch.Tensor\n",
    "        输入数据.\n",
    "\n",
    "    Y_label : torch.Tensor\n",
    "        标签数据.\n",
    "\n",
    "    loss_func : torch.nn.modules.loss\n",
    "        损失函数.\n",
    "\n",
    "    args : argparse.Namespace\n",
    "        包含超参数的命名空间对象.\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    grad_dict : dict\n",
    "        存储经过裁剪和加噪的参数梯度字典.\n",
    "    \"\"\"\n",
    "    batch_data_num = len(X_data)\n",
    "    batch_data_parameters_grad_dict = {}\n",
    "\n",
    "    # 对于每个样本，计算其梯度并进行裁剪\n",
    "    for data_idx, (per_data, per_label) in enumerate(zip(X_data, Y_label)):\n",
    "        per_data_parameters_grad_dict = {}\n",
    "        output = model(per_data.unsqueeze(0))  # 为单样本增加 batch 维度\n",
    "        loss = loss_func(output, per_label.unsqueeze(0))  # 损失计算\n",
    "        loss.backward()\n",
    "\n",
    "        # 计算每个样本梯度范数\n",
    "        model_parameter_grad_norm = 0.0\n",
    "        with torch.no_grad():\n",
    "            for name, param in model.named_parameters():\n",
    "                model_parameter_grad_norm += (torch.norm(param.grad) ** 2).item()\n",
    "                per_data_parameters_grad_dict[name] = param.grad.clone().detach()\n",
    "            model_parameter_grad_norm = np.sqrt(model_parameter_grad_norm)\n",
    "\n",
    "            # 梯度裁剪\n",
    "            for name in per_data_parameters_grad_dict:\n",
    "                per_data_parameters_grad_dict[name] /= max(1, model_parameter_grad_norm / args.C)\n",
    "                if name not in batch_data_parameters_grad_dict:\n",
    "                    batch_data_parameters_grad_dict[name] = per_data_parameters_grad_dict[name]\n",
    "                else:\n",
    "                    batch_data_parameters_grad_dict[name] += per_data_parameters_grad_dict[name]\n",
    "\n",
    "            # 清零模型梯度\n",
    "            for param in model.parameters():\n",
    "                param.grad.zero_()\n",
    "\n",
    "    # 对批次梯度添加噪声\n",
    "    for name in batch_data_parameters_grad_dict:\n",
    "        batch_data_parameters_grad_dict[name] += torch.randn(\n",
    "            batch_data_parameters_grad_dict[name].shape).to(args.device) * args.C * args.noise_sigma\n",
    "        batch_data_parameters_grad_dict[name] /= batch_data_num\n",
    "\n",
    "    return batch_data_parameters_grad_dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def dp_sgd_update_model(model, grad_dict, args):\n",
    "    \"\"\"\n",
    "    使用差分隐私梯度更新模型参数。\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    model : torch.nn.Module\n",
    "        训练模型.\n",
    "\n",
    "    grad_dict : dict\n",
    "        存储参数梯度的字典.\n",
    "\n",
    "    args : argparse.Namespace\n",
    "        包含超参数的命名空间对象.\n",
    "    \"\"\"\n",
    "    with torch.no_grad():\n",
    "        for name, param in model.named_parameters():\n",
    "            param -= args.lr * grad_dict[name]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 差分隐私训练\n",
    "def dp_train_gru(model, train_loader, loss_func, args, accountant):\n",
    "    model.train()\n",
    "\n",
    "    for batch_idx, (X_data, Y_label) in enumerate(train_loader):\n",
    "        # 将数据展平并移至设备，确保类型为 LongTensor\n",
    "        X_data = X_data.view(X_data.size(0), -1).long().to(args.device)  # 转换为 LongTensor\n",
    "        Y_label = Y_label.to(args.device)\n",
    "\n",
    "        # DP 梯度计算\n",
    "        grad_dict = dp_sgd_train_step(model, X_data, Y_label, loss_func, args)\n",
    "\n",
    "        # 更新模型\n",
    "        dp_sgd_update_model(model, grad_dict, args)\n",
    "\n",
    "        if (batch_idx + 1) % 30 == 0:\n",
    "            print(f\"Batch {batch_idx + 1}, Loss: {loss_func(model(X_data), Y_label).item():.6f}\")\n",
    "\n",
    "    # 计算隐私损失\n",
    "    epsilon = compute_privacy_loss(accountant, args.noise_sigma, args.batch_size / len(train_loader.dataset),\n",
    "                                   len(train_loader) * args.epochs, args.delta)\n",
    "    print(f\"(epsilon = {epsilon:.2f}, delta = {args.delta})\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 测试函数\n",
    "def test_gru(model, test_loader, loss_func, args):\n",
    "    model.eval()\n",
    "    test_loss = 0\n",
    "    correct = 0\n",
    "\n",
    "    with torch.no_grad():\n",
    "        for X_data, Y_label in test_loader:\n",
    "            X_data = X_data.view(X_data.size(0), -1).to(args.device)  # 展平\n",
    "            Y_label = Y_label.to(args.device)\n",
    "            output = model(X_data)\n",
    "            test_loss += loss_func(output, Y_label).item()\n",
    "            pred = output.argmax(dim=1, keepdim=True)\n",
    "            correct += pred.eq(Y_label.view_as(pred)).sum().item()\n",
    "\n",
    "    test_loss /= len(test_loader.dataset)\n",
    "    accuracy = 100. * correct / len(test_loader.dataset)\n",
    "\n",
    "    print(f\"\\nTest set: Average loss: {test_loss:.4f}, Accuracy: {correct}/{len(test_loader.dataset)} ({accuracy:.2f}%)\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 主程序\n",
    "def main():\n",
    "    # 参数设置\n",
    "    class Args:\n",
    "        batch_size = 64\n",
    "        epochs = 3\n",
    "        lr = 0.1\n",
    "        device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
    "        vocab_size = 28  # 假设输入是 MNIST 每行作为时间步\n",
    "        embed_dim = 128\n",
    "        hidden_dim = 100\n",
    "        output_dim = 10\n",
    "        noise_sigma = 1.2\n",
    "        C = 1.0\n",
    "        delta = 1e-5\n",
    "\n",
    "    args = Args()\n",
    "\n",
    "    # 模型、损失函数、数据加载器和隐私统计器\n",
    "    model = GRUModel(args.vocab_size, args.embed_dim, args.hidden_dim, args.output_dim).to(args.device)\n",
    "    loss_func = nn.CrossEntropyLoss()\n",
    "    train_loader, test_loader = load_dataset(args.batch_size)\n",
    "    accountant = MomentsAccountant()\n",
    "\n",
    "    # 训练和测试\n",
    "    for epoch in tqdm(range(1, args.epochs + 1)):\n",
    "        print(f\"Epoch {epoch}\")\n",
    "        dp_train_gru(model, train_loader, loss_func, args, accountant)\n",
    "        test_gru(model, test_loader, loss_func, args)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0%|          | 0/3 [00:00<?, ?it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "  0%|          | 0/3 [01:27<?, ?it/s]\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m                         Traceback (most recent call last)",
      "\u001b[1;32m/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb Cell 12\u001b[0m line \u001b[0;36m1\n\u001b[0;32m----> <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=0'>1</a>\u001b[0m main()\n",
      "\u001b[1;32m/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb Cell 12\u001b[0m line \u001b[0;36m2\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=25'>26</a>\u001b[0m \u001b[39mfor\u001b[39;00m epoch \u001b[39min\u001b[39;00m tqdm(\u001b[39mrange\u001b[39m(\u001b[39m1\u001b[39m, args\u001b[39m.\u001b[39mepochs \u001b[39m+\u001b[39m \u001b[39m1\u001b[39m)):\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=26'>27</a>\u001b[0m     \u001b[39mprint\u001b[39m(\u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mEpoch \u001b[39m\u001b[39m{\u001b[39;00mepoch\u001b[39m}\u001b[39;00m\u001b[39m\"\u001b[39m)\n\u001b[0;32m---> <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=27'>28</a>\u001b[0m     dp_train_gru(model, train_loader, loss_func, args, accountant)\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=28'>29</a>\u001b[0m     test_gru(model, test_loader, loss_func, args)\n",
      "\u001b[1;32m/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb Cell 12\u001b[0m line \u001b[0;36m1\n\u001b[1;32m      <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=7'>8</a>\u001b[0m Y_label \u001b[39m=\u001b[39m Y_label\u001b[39m.\u001b[39mto(args\u001b[39m.\u001b[39mdevice)\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=9'>10</a>\u001b[0m \u001b[39m# DP 梯度计算\u001b[39;00m\n\u001b[0;32m---> <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=10'>11</a>\u001b[0m grad_dict \u001b[39m=\u001b[39m dp_sgd_train_step(model, X_data, Y_label, loss_func, args)\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=12'>13</a>\u001b[0m \u001b[39m# 更新模型\u001b[39;00m\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=13'>14</a>\u001b[0m dp_sgd_update_model(model, grad_dict, args)\n",
      "\u001b[1;32m/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb Cell 12\u001b[0m line \u001b[0;36m3\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=30'>31</a>\u001b[0m \u001b[39mfor\u001b[39;00m data_idx, (per_data, per_label) \u001b[39min\u001b[39;00m \u001b[39menumerate\u001b[39m(\u001b[39mzip\u001b[39m(X_data, Y_label)):\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=31'>32</a>\u001b[0m     per_data_parameters_grad_dict \u001b[39m=\u001b[39m {}\n\u001b[0;32m---> <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=32'>33</a>\u001b[0m     output \u001b[39m=\u001b[39m model(per_data\u001b[39m.\u001b[39;49munsqueeze(\u001b[39m0\u001b[39;49m))  \u001b[39m# 为单样本增加 batch 维度\u001b[39;00m\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=33'>34</a>\u001b[0m     loss \u001b[39m=\u001b[39m loss_func(output, per_label\u001b[39m.\u001b[39munsqueeze(\u001b[39m0\u001b[39m))  \u001b[39m# 损失计算\u001b[39;00m\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=34'>35</a>\u001b[0m     loss\u001b[39m.\u001b[39mbackward()\n",
      "File \u001b[0;32m/opt/anaconda3/envs/science39/lib/python3.9/site-packages/torch/nn/modules/module.py:1511\u001b[0m, in \u001b[0;36mModule._wrapped_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m   1509\u001b[0m     \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_compiled_call_impl(\u001b[39m*\u001b[39margs, \u001b[39m*\u001b[39m\u001b[39m*\u001b[39mkwargs)  \u001b[39m# type: ignore[misc]\u001b[39;00m\n\u001b[1;32m   1510\u001b[0m \u001b[39melse\u001b[39;00m:\n\u001b[0;32m-> 1511\u001b[0m     \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_call_impl(\u001b[39m*\u001b[39;49margs, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n",
      "File \u001b[0;32m/opt/anaconda3/envs/science39/lib/python3.9/site-packages/torch/nn/modules/module.py:1520\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m   1515\u001b[0m \u001b[39m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m   1516\u001b[0m \u001b[39m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m   1517\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m (\u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_backward_hooks \u001b[39mor\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_backward_pre_hooks \u001b[39mor\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_forward_hooks \u001b[39mor\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_forward_pre_hooks\n\u001b[1;32m   1518\u001b[0m         \u001b[39mor\u001b[39;00m _global_backward_pre_hooks \u001b[39mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m   1519\u001b[0m         \u001b[39mor\u001b[39;00m _global_forward_hooks \u001b[39mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1520\u001b[0m     \u001b[39mreturn\u001b[39;00m forward_call(\u001b[39m*\u001b[39;49margs, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n\u001b[1;32m   1522\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m   1523\u001b[0m     result \u001b[39m=\u001b[39m \u001b[39mNone\u001b[39;00m\n",
      "\u001b[1;32m/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb Cell 12\u001b[0m line \u001b[0;36m1\n\u001b[1;32m      <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=8'>9</a>\u001b[0m \u001b[39mdef\u001b[39;00m \u001b[39mforward\u001b[39m(\u001b[39mself\u001b[39m, x):\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=9'>10</a>\u001b[0m     x \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39membedding(x)\n\u001b[0;32m---> <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=10'>11</a>\u001b[0m     _, h_n \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mgru(x)  \u001b[39m# 仅取最终隐藏状态\u001b[39;00m\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=11'>12</a>\u001b[0m     x \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mfc(h_n\u001b[39m.\u001b[39msqueeze(\u001b[39m0\u001b[39m))\n\u001b[1;32m     <a href='vscode-notebook-cell://localhost:8080/root/MyCode/trashbin/Deep_Learning_with_Differential_Privacy.ipynb#X12sdnNjb2RlLXJlbW90ZQ%3D%3D?line=12'>13</a>\u001b[0m     \u001b[39mreturn\u001b[39;00m x\n",
      "File \u001b[0;32m/opt/anaconda3/envs/science39/lib/python3.9/site-packages/torch/nn/modules/module.py:1511\u001b[0m, in \u001b[0;36mModule._wrapped_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m   1509\u001b[0m     \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_compiled_call_impl(\u001b[39m*\u001b[39margs, \u001b[39m*\u001b[39m\u001b[39m*\u001b[39mkwargs)  \u001b[39m# type: ignore[misc]\u001b[39;00m\n\u001b[1;32m   1510\u001b[0m \u001b[39melse\u001b[39;00m:\n\u001b[0;32m-> 1511\u001b[0m     \u001b[39mreturn\u001b[39;00m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_call_impl(\u001b[39m*\u001b[39;49margs, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n",
      "File \u001b[0;32m/opt/anaconda3/envs/science39/lib/python3.9/site-packages/torch/nn/modules/module.py:1520\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m   1515\u001b[0m \u001b[39m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m   1516\u001b[0m \u001b[39m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m   1517\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mnot\u001b[39;00m (\u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_backward_hooks \u001b[39mor\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_backward_pre_hooks \u001b[39mor\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_forward_hooks \u001b[39mor\u001b[39;00m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_forward_pre_hooks\n\u001b[1;32m   1518\u001b[0m         \u001b[39mor\u001b[39;00m _global_backward_pre_hooks \u001b[39mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m   1519\u001b[0m         \u001b[39mor\u001b[39;00m _global_forward_hooks \u001b[39mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1520\u001b[0m     \u001b[39mreturn\u001b[39;00m forward_call(\u001b[39m*\u001b[39;49margs, \u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mkwargs)\n\u001b[1;32m   1522\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m   1523\u001b[0m     result \u001b[39m=\u001b[39m \u001b[39mNone\u001b[39;00m\n",
      "File \u001b[0;32m/opt/anaconda3/envs/science39/lib/python3.9/site-packages/torch/nn/modules/rnn.py:1100\u001b[0m, in \u001b[0;36mGRU.forward\u001b[0;34m(self, input, hx)\u001b[0m\n\u001b[1;32m   1098\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mcheck_forward_args(\u001b[39minput\u001b[39m, hx, batch_sizes)\n\u001b[1;32m   1099\u001b[0m \u001b[39mif\u001b[39;00m batch_sizes \u001b[39mis\u001b[39;00m \u001b[39mNone\u001b[39;00m:\n\u001b[0;32m-> 1100\u001b[0m     result \u001b[39m=\u001b[39m _VF\u001b[39m.\u001b[39;49mgru(\u001b[39minput\u001b[39;49m, hx, \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_flat_weights, \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mbias, \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mnum_layers,\n\u001b[1;32m   1101\u001b[0m                      \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mdropout, \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mtraining, \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mbidirectional, \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49mbatch_first)\n\u001b[1;32m   1102\u001b[0m \u001b[39melse\u001b[39;00m:\n\u001b[1;32m   1103\u001b[0m     result \u001b[39m=\u001b[39m _VF\u001b[39m.\u001b[39mgru(\u001b[39minput\u001b[39m, batch_sizes, hx, \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_flat_weights, \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mbias,\n\u001b[1;32m   1104\u001b[0m                      \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mnum_layers, \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mdropout, \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mtraining, \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mbidirectional)\n",
      "\u001b[0;31mKeyboardInterrupt\u001b[0m: "
     ]
    }
   ],
   "source": [
    "main()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "mathmodal",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
